package com.pp.demo.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.pp.demo.common.constant.AuthErrorCode;
import com.pp.demo.common.constant.ErrorCode;
import com.pp.demo.common.utils.JwtUtils;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.SignatureException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtUtils jwtUtils;
    private final SecurityProperties securityProperties;
    private final PathMatcher pathMatcher = new AntPathMatcher();

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        String requestURI = request.getRequestURI();
        log.debug("请求路径: {}", requestURI);
        try {
            // 检查是否是忽略路径
            if (isIgnorePath(requestURI)) {
                filterChain.doFilter(request, response);
                return;
            }

            // 从请求头获取令牌
            String jwt = getJwtFromRequest(request);
            log.debug("令牌: {}", jwt);
            if (!StringUtils.hasText(jwt)) {
                log.warn("JWT令牌缺失");
                sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, AuthErrorCode.TOKEN_NOT_FOUND);
                return;
            }

            // 验证令牌
            if (jwtUtils.validateToken(jwt)) {
                // 解析令牌获取系统信息
                String systemId = jwtUtils.getSystemId(jwt);
                String systemName = jwtUtils.getSystemName(jwt);

                // 创建认证对象并设置到SecurityContext
                Authentication authentication = new UsernamePasswordAuthenticationToken(systemName, null, Collections.emptyList());
                SecurityContextHolder.getContext().setAuthentication(authentication);
                log.debug("JWT认证成功，系统ID: {}, 系统名称: {}", systemId, systemName);
            }
        } catch (ExpiredJwtException ex) {
            log.warn("JWT令牌已过期: {}", ex.getMessage());
            sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, AuthErrorCode.TOKEN_EXPIRED);
            return;
        } catch (UnsupportedJwtException | MalformedJwtException | SignatureException ex) {
            log.warn("无效的JWT令牌: {}", ex.getMessage());
            sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, AuthErrorCode.TOKEN_INVALID);
            return;
        } catch (IllegalArgumentException ex) {
            log.warn("JWT令牌参数异常: {}", ex.getMessage());
            sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, AuthErrorCode.TOKEN_INVALID);
            return;
        } catch (Exception ex) {
            log.error("JWT认证失败: {}", ex);
            sendErrorResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, AuthErrorCode.TOKEN_VALIDATION_ERROR);
            return;
        }

        filterChain.doFilter(request, response);
    }

    /**
     * 从请求头中获取JWT令牌
     */
    private String getJwtFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken)) {
            return StringUtils.replace(bearerToken, "Bearer ", "");
        }
        return null;
    }

    /**
     * 检查请求路径是否在忽略列表中
     */
    private boolean isIgnorePath(String requestUri) {
        return securityProperties.getProcessedExcludedPaths().stream()
                .anyMatch(pattern -> pathMatcher.match(pattern, requestUri));
    }

    /**
     * 发送错误响应
     */
    private void sendErrorResponse(HttpServletResponse response, int status, ErrorCode codeEnum) throws IOException {
        response.setStatus(status);
        response.setContentType("application/json;charset=UTF-8");

        Map<String, Object> errorResponse = new HashMap<>();
        errorResponse.put("code", codeEnum.getCode());
        errorResponse.put("msg", codeEnum.getMessage());

        ObjectMapper objectMapper = new ObjectMapper();
        response.getWriter().write(objectMapper.writeValueAsString(errorResponse));
    }
}
